﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Modules.Project.Entitys;
using Modules.Project.Repositories;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Exceptions;
using System.Net.Mail;

namespace Modules.Project
{
    [UseDI(ServiceLifetime.Scoped)]
    public class ProjectGuaranteePaymentService
    {
        private readonly ProjectGuaranteeAccountService projectGuaranteeAccountService;
        private readonly ProjectGuaranteePaymentRepository repository;
        private readonly ProjectAttachmentService projectAttachmentService;
        private readonly IApplicationContext applicationContext;
        private readonly ILogger logger;

        public ProjectGuaranteePaymentService(ProjectGuaranteePaymentRepository repository, ProjectAttachmentService projectAttachmentService, ProjectGuaranteeAccountService projectGuaranteeAccountService, IApplicationContext applicationContext, ILogger<ProjectGuaranteePaymentService> logger)
        {
            this.repository = repository;
            this.projectAttachmentService = projectAttachmentService;
            this.projectGuaranteeAccountService = projectGuaranteeAccountService;
            this.applicationContext = applicationContext;
            this.logger = logger;
        }

        public ProjectGuaranteePayment? GetProjectGuaranteePayment(int id)
        {
            return repository.Get(id);
        }

        public void Create(ProjectGuaranteePayment entity, IEnumerable<string> attachments)
        {
            try
            {
                applicationContext.Transaction.Begin();
                if (entity.Paid != null && entity.Payable != null && entity.Payable == entity.Paid)
                {
                    entity.DepositeType = 缴存类型.按预设比例缴存;
                }
                if (entity.Paid != null && entity.Payable != null && entity.Payable < entity.Paid)
                {
                    entity.DepositeType = 缴存类型.增加保证金应缴金额;
                }
                if (entity.Paid != null && entity.Payable != null && entity.Payable > entity.Paid)
                {
                    entity.DepositeType = 缴存类型.减少保证金应交金额;
                }
                if (entity.Paid != null && entity.Payable != null && entity.Paid == 0)
                {
                    entity.DepositeType = 缴存类型.免除保证金;
                }
                var account = projectGuaranteeAccountService.GetProjectGuaranteeAccount(entity.GuaranteeAccountId) ?? throw new BusinessException("保证金账户不存在");
                entity.GuaranteeAccountType = account.Type;
                if (entity.GuaranteeAccountType == 保证金类型.保证金账户)
                {
                    entity.Balance = entity.Paid ?? 0;
                }
                repository.Insert(entity);

                #region 附件

                foreach (var item in attachments)
                {
                    ProjectAttachment projectAttachment = new()
                    {
                        Id = Guid.NewGuid().ToString().Replace("-", ""),
                        AttachmentId = item,
                        ObjectId = entity.Id.ToString(),
                        Tenant = 项目附件租户.ProjectGuaranteePayment,
                        AttachmentType = 附件类型.保证金保函凭证,
                        CreateTime = DateTime.Now
                    };
                    projectAttachmentService.Create(projectAttachment);
                }

                #endregion 附件

                applicationContext.Transaction.Complete();
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();
                logger.LogError(ex, $"创建保证金账户失败");
                throw new BusinessException("创建保证金账户失败");
            }
        }

        /// <summary>
        /// 审核
        /// </summary>
        /// <param name="entity"></param>
        public void Audit(ProjectGuaranteePayment entity)
        {
            try
            {
                applicationContext.Transaction.Begin();
                repository.Update(entity);
                applicationContext.Transaction.Complete();
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();
                logger.LogError(ex, $"审核保证金账户失败");
                throw new BusinessException("审核保证金账户失败");
            }
        }

        public void Update(ProjectGuaranteePayment entity, IEnumerable<string> attachments)
        {
            try
            {
                applicationContext.Transaction.Begin();
                if (entity.Paid == 0)
                {
                    entity.DepositeType = 缴存类型.免除保证金;
                }
                if (entity.Paid != null && entity.Payable != null && entity.Payable == entity.Paid)
                {
                    entity.DepositeType = 缴存类型.按预设比例缴存;
                }
                if (entity.Paid != null && entity.Payable != null && entity.Payable < entity.Paid)
                {
                    entity.DepositeType = 缴存类型.增加保证金应缴金额;
                }
                if (entity.Paid != null && entity.Payable != null && entity.Payable > entity.Paid)
                {
                    entity.DepositeType = 缴存类型.减少保证金应交金额;
                }
                if (entity.GuaranteeAccountType == 保证金类型.保证金账户)
                {
                    entity.Balance = entity.Paid ?? 0;
                }

                repository.Update(entity);

                #region 附件

                if (attachments.Count() > 0)
                {
                    List<ProjectAttachment> projectAttachments = projectAttachmentService.GetProjectAttachmentsByObjectIdAndType(entity.Id, 附件类型.保证金保函凭证, 项目附件租户.ProjectGuaranteePayment).ToList();
                    projectAttachmentService.Deleted(projectAttachments.Select(i => i.Id));
                    foreach (var item in attachments)
                    {
                        ProjectAttachment projectAttachment = new()
                        {
                            Id = Guid.NewGuid().ToString().Replace("-", ""),
                            AttachmentId = item,
                            ObjectId = entity.Id.ToString(),
                            Tenant = 项目附件租户.ProjectGuaranteePayment,
                            AttachmentType = 附件类型.保证金保函凭证,
                            CreateTime = DateTime.Now
                        };
                        projectAttachmentService.Create(projectAttachment);
                    }
                }

                #endregion 附件

                applicationContext.Transaction.Complete();
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();
                logger.LogError(ex, $"修改保证金账户失败");
                throw new BusinessException("修改保证金账户失败");
            }
        }

        public void Update(ProjectGuaranteePayment entity)
        {
            repository.Update(entity);
        }

        public IPagedList<ProjectGuaranteePayment> GetProjectGuaranteePayments(ProjectGuaranteePaymentQuery query, int pageIndex, int pageSize)
        {
            return repository.GetProjectGuaranteePayments(query, pageIndex, pageSize);
        }

        public IEnumerable<ProjectGuaranteePayment> GetProjectGuaranteePayments(int guaranteeAccountId)
        {
            return repository.GetProjectGuaranteePayments(guaranteeAccountId);
        }

        public IEnumerable<ProjectGuaranteePayment> GetProjectGuaranteePayments(IEnumerable<int> ids)
        {
            return repository.PopulateEntitiesByEntityIds(ids);
        }

        public ProjectGuaranteePayment? GetProjectGuaranteePaymentByProjectId(int projectId)
        {
            return repository.GetProjectGuaranteePaymentByProjectId(projectId);
        }

        public IEnumerable<ProjectGuaranteePayment> GetProjectGuaranteePaymentsByProjectIds(IEnumerable<int> projectIds)
        {
            return repository.GetProjectGuaranteePaymentsByProjectIds(projectIds);
        }

        public int GetProjectGuaranteePaymentCount(ProjectGuaranteePaymentQuery query)
        {
            return repository.GetProjectGuaranteePaymentCount(query);
        }

        public bool ExistProjectGuaranteePayment(int projectId)
        {
            return repository.ExistProjectGuaranteePayment(projectId);
        }

        public void MarkPaymentExpire()
        {
            var list = repository.MarkPaymentExpire();
            foreach (var item in list)
            {
                item.Status = 保证金状态.失效;
                repository.Update(item);
            }
        }

        /// <summary>
        /// 通过缴存Id判断该缴纳信息的账户类型是否正确
        /// </summary>
        /// <param name="paymentId"></param>
        /// <param name="accoungType"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public bool VerifyAccountTypeByPaymentId(int paymentId, 保证金类型 accoungType)
        {
            var payment = GetProjectGuaranteePayment(paymentId) ?? throw new BusinessException("保证金缴纳信息不存在");
            var account = projectGuaranteeAccountService.GetProjectGuaranteeAccount(payment.GuaranteeAccountId) ?? throw new BusinessException("保证金账户不存在");
            return account.Type == accoungType;
        }

        public void Delete(int id)
        {
            var data = repository.Get(id) ?? throw new BusinessException("保证金缴纳信息不存在");
            if (data.Status == 保证金状态.有效 || data.Status == 保证金状态.失效) throw new BusinessException("该保证金缴纳信息不允许删除");
            repository.DeleteByEntityId(id);
        }

        public void Deleted(IEnumerable<int> ids)
        {
            foreach (int id in ids)
            {
                Delete(id);
            }
        }

        public IEnumerable<ProjectGuaranteePayment> GetProjectGuaranteePaymentsByStatus(保证金退还状态 status)
        {
            return repository.GetProjectGuaranteePaymentsByStatus(status);
        }
    }
}